package com.z996.bean;

import com.z996.anotation.Bean;
import com.z996.anotation.Di;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 简述:<br>
 * 注解应用容器
 *
 * @Author zfh18
 * @Date 2024-03-01 23:30
 * @Version 1.0
 **/
public class AnotationApplicationContext implements ApplicationContext {
    public Map<Class, Object> beanFactory = new HashMap<>();
    private static String rootPath;

    public AnotationApplicationContext(String configLocation) throws Exception {
        if (configLocation.isEmpty() || configLocation.isBlank()) {
            throw new RuntimeException("配置扫描路径不能为空");
        }
        // 在java 中 , \\ 代表转义符号  \\\\  代表转义 反斜杠(\)
        String packageDirName = configLocation.replaceAll("\\.", "\\\\");

        Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
        while (resources.hasMoreElements()) {
            URL url = resources.nextElement();
            String filePath = URLDecoder.decode(url.getFile(), "utf-8");
            // 获取父路径
            rootPath = filePath.substring(0, filePath.length() - packageDirName.length());
            loadBean(new File(filePath));
        }
        loadDi();
    }

    public void loadBean(File file) {
        // 先判断 是否文件夹
        if (file.isDirectory()) {
            // 获取文件夹内所有资源
            File[] childrenFiles = file.listFiles();
            // 判断文件夹是否有资源
            if (childrenFiles == null || childrenFiles.length == 0) {
                return;
            }
            for (File child : childrenFiles) {
                if (child.isDirectory()) {
                    // 如果还是文件夹则递归调用
                    loadBean(child);
                } else {
                    //通过文件路径转变成全类名,第一步把绝对路径部分去掉
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                    if (pathWithClass.contains(".class")) {
                        pathWithClass = pathWithClass.replaceAll("\\\\", "\\.").replaceAll(".class", "");
                        try {
                            Class<?> aClass = Class.forName(pathWithClass);
                            //把非接口的类实例化放在map中
                            if (!aClass.isInterface()) {
                                // 获取类是否含义 @bean注解
                                Bean annotation = aClass.getAnnotation(Bean.class);
                                if (annotation != null) {
                                    Constructor<?> aClassDeclaredConstructor = aClass.getDeclaredConstructor();
                                    aClassDeclaredConstructor.setAccessible(true);
                                    Object instance = aClassDeclaredConstructor.newInstance();

                                    //判断一下有没有接口
                                    if (aClass.getInterfaces().length > 0) {
                                        //如果有接口把接口的class当成key，实例对象当成value
                                        System.out.println("正在加载【" + aClass.getInterfaces()[0] + "】,实例对象是：" + instance.getClass().getName());


                                        beanFactory.put(aClass.getInterfaces()[0], instance);

                                    } else {
                                        //如果有接口把自己的class当成key，实例对象当成value
                                        System.out.println("正在加载【" + aClass.getName() + "】,实例对象是：" + instance.getClass().getName());

                                        beanFactory.put(aClass, instance);

                                    }
                                }

                            }
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    }
                }

            }
        }

    }

    /**
     * 依赖注入
     */
    private void loadDi() {
        for (Map.Entry<Class, Object> entry : beanFactory.entrySet()) {
            //就是咱们放在容器的对象
            Object obj = entry.getValue();
            Class<?> aClass = obj.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields) {
                Di annotation = field.getAnnotation(Di.class);
                if (annotation != null) {
                    field.setAccessible(true);
                    try {
                        System.out.println("正在给【" + obj.getClass().getName() + "】属性【" + field.getName() + "】注入值【" + beanFactory.get(field.getType()).getClass().getName() + "】");
                        field.set(obj, beanFactory.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    public static void main(String[] args) throws Exception {
        AnotationApplicationContext anotationApplicationContext = new AnotationApplicationContext("com.z996");

    }

}
